package com.hxht.cmp.controller;

import com.github.pagehelper.Page;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.hxht.cmp.common.Constants;
import com.hxht.cmp.common.enums.ResultCode;
import com.hxht.cmp.common.result.ResultResponse;
import com.hxht.cmp.entity.*;
import com.hxht.cmp.pojo.ScreenshotPojo;
import com.hxht.cmp.pojo.SearchCriteria;
import com.hxht.cmp.service.CasePlanService;
import com.hxht.cmp.service.CaseVideoService;
import com.hxht.cmp.service.ImageLoadService;
import com.hxht.cmp.service.VideoService;
import com.hxht.cmp.utils.DateUtils;
import com.hxht.cmp.utils.TimeLineThread;
import org.apache.shiro.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;

/**
 * Created by gaozikun on 2017/9/6 0006.
 */
@RestController
@RequestMapping("image")
public class ImageLoadController {
    private final Logger logger = LoggerFactory.getLogger(ImageLoadController.class);
    @Autowired
    private CaseVideoService caseVideoService;
    @Autowired
    private CasePlanService casePlanService;
    @Autowired
    private ImageLoadService imageLoadService;
    @Resource
    private VideoService videoService;

    /**
     * 多线程时间轴截图
     *
     * @param uid
     * @param timeSize
     * @return
     */
    @RequestMapping("/timeline2")
    public ResultResponse timeline2(String uid, long timeSize) {
        Video video = videoService.selectByUid(uid);
        if (ObjectUtils.isEmpty(video)) {
            return ResultResponse.init(1, "视频记录未找到");
        }
        List<String> picAddress = new ArrayList<>();

        timeSize = timeSize % 20 > 0 ? timeSize - timeSize % 20 : timeSize;
        String path = Constants.TIMELINE_PATH + "/" + video.getUid() + "/";
        String TIME_LINE = Constants.TIMELINE_PATH.replace("usr/local/movies/", "cmpImages/");
        File f = new File(path);
        //判断文件夹是否存在
        if (!f.exists()) {
            logger.info(path + "   文件夹不存在 ,进行创建,创建文件数量:" + timeSize / 20);
            f.mkdirs();
        }
        logger.info(path + "   文件夹存在 ,不进行创建,创建文件数量:" + timeSize / 20);
        String returnPath = "http://" + Constants.CENTRAL_IP + ":" + Constants.CENTRAL_PORT + TIME_LINE + "/" + video.getUid() + "/";
//        logger.info("return path :" + returnPath);
        File fa[] = f.listFiles();
        if ((fa != null ? fa.length : 0) > 0 && fa.length == timeSize / 20) {
            logger.info(path + "  文件数量足够,准备直接返回 ");
            for (long i = 0; i < timeSize; i += 20) {
                picAddress.add(returnPath + String.format("%08d", i) + ".png");
            }
            return ResultResponse.success(picAddress);
        }
        //执行多线程截图任务
        ExecutorService executor = Executors.newFixedThreadPool(60);
        for (long i = 0; i < timeSize; i += 20) {
            logger.info("创建截图任务" + i + " 进行截图");
            TimeLineThread lineThread = new TimeLineThread(i, video);
            executor.submit(lineThread, null);
            picAddress.add(returnPath + String.format("%08d", i) + ".png");
        }
        try {
            int tally = 0;
            logger.info(String.valueOf(System.currentTimeMillis()));
            while (executor.awaitTermination(5, TimeUnit.SECONDS) || (tally++ > 10)) {
                logger.info(String.valueOf(System.currentTimeMillis()));
                executor.shutdown();
            }
        } catch (InterruptedException e) {
            logger.error("截图等待产生了错误,错误信息:" + e.getMessage());
        }
        //构造虚假的地址返回,任务持续执行
        return ResultResponse.success(picAddress);
    }

    @RequestMapping("download")
    public void download(HttpServletResponse response, String url, String filename) {
        try {
            response.setContentType("application/octet-stream");
            response.setHeader("content-disposition", "attachment;filename=" + filename);
            URL uri = new URL(url);
//            File file = new File(url);
            InputStream in = uri.openStream();
            int len;
            byte[] buffer = new byte[1024];
            OutputStream out = response.getOutputStream();
            while ((len = in.read(buffer)) > 0) {
                out.write(buffer, 0, len);//将缓冲区的数据输出到客户端浏览器
            }
            in.close();
        } catch (Exception e) {
            logger.error("下载文件出错:" + e.getMessage());
        }
    }

    // 抓拍接口
    @RequestMapping("catchImage")
    public ResultResponse catchImage(Integer time, String url, String planUid) {
        // 把秒数转成时分秒
        String timeStr = DateUtils.secToTime(time);
        // 注意获取文件名称的时候，不要重,要加锁
        Long name;
        synchronized (ImageLoadController.class) {
            name = new Date().getTime();
        }
        // 保存图片
        Map<String, Object> map = new HashMap<>();
        map.put("planUid", planUid);
        //根据播放url截取到通道号
//        map.put("chn", sub(url));
        // 存储位置
        String prefix = "/usr/local/movies/images/";
        // 创建多级目录
        String path = mkdir(prefix);
        // 文件相对根目录的位置
        Screenshot imageLoad = new Screenshot();
        imageLoad.setPath(mkdir("images/") + "/" + name + ".jpg");
        // 调用抓拍命令
        String strCmd = Constants.FFMPEG_DIR + "ffmpeg -ss " + timeStr + " -i " + url + " -f image2 -y " + path + "/" + name + ".jpg";

        // 这边注意

        map.put("playUrl", url);
        Video record = caseVideoService.getVideoInfoByChn(map);

        // 通道名称
        imageLoad.setChannelsName(record.getChannelsName());
        //Video表uid
        imageLoad.setVideoUid(record.getUid());
        // 类型--1表示图片，2表示视频
        imageLoad.setType("1");

        User user1 = (User) SecurityUtils.getSubject().getSession().getAttribute("user");
        String userUid = user1.getUid();
        // 用户编号
        imageLoad.setCreatUserUid(userUid);
        // 创建人
        Plan planInfo = casePlanService.selectPlanByUid(planUid);
        Case caseInfo = casePlanService.selectCaseByUid(planInfo.getCaseUid());
        // 案号
        //案件类型
        imageLoad.setCaseType(Constants.CASE_TYPE_MAP.get(caseInfo.getCategory()).getName());
        // 截图开始时间
        imageLoad.setStartTime(time);
        //caseUid
        imageLoad.setCaseUid(caseInfo.getUid());
        //创建和更新时间
        imageLoad.setDateCreated(new Date());
        imageLoad.setLastUpdated(new Date());
        // 法官信息
        imageLoad.setJudgeUserUid(planInfo.getJudgeUserUid());
        //书记员信息
        imageLoad.setSecretaryUserUid(planInfo.getSecretaryUserUid());

        String message;
        Process p = null;
        try {
            p = Runtime.getRuntime().exec(strCmd);
            // 进行阻塞
            p.waitFor();
            message = "抓怕成功";
            imageLoadService.insert(imageLoad);
        } catch (Exception e) {
            logger.error(e.getMessage());
            return ResultResponse.failed();
        } finally {
            if (null != p) {
                // 释放资源
                try {
                    p.getErrorStream().close();
                    p.getOutputStream().close();
                    p.getInputStream().close();
                    p.destroy();
                } catch (IOException e) {
                    logger.error(e.getMessage());
                }

            }
        }
        // 返回服务器ip地址
        JsonObject obj = new JsonObject();
        obj.addProperty("name", name + ".jpg");
        obj.addProperty("ip", Constants.CENTRAL_IP);
        return ResultResponse.init(0, message, obj);
    }

    // 截图接口
    @RequestMapping("subVideo")
    @ResponseBody
    public ResultResponse subVideo(Integer start, Integer end, String url, String planUid) {
        // 把秒数转成时分秒
        String startStr = DateUtils.secToTime(start);
        String endStr = DateUtils.secToTime(end);
        Long name = 0l;
        synchronized (ImageLoadController.class) {
            name = new Date().getTime();
        }
        // 存储位置
        String prefix = "/usr/local/movies/videos/";
        // 创建多级目录
        String path = mkdir(prefix);
        // 文件相对根目录的位置
        Screenshot imageLoad = new Screenshot();
        imageLoad.setPath(mkdir("videos/") + "/" + name + ".mp4");
        // 调用抓拍命令
        String strCmd = Constants.FFMPEG_DIR + "ffmpeg  -i " + url + " -vcodec copy -acodec copy -ss " + startStr + " -to " + endStr + " " + path + "/" + name + ".mp4 -y";
        logger.info(strCmd);
        // 保存图片
        Map<String, Object> map = new HashMap<>();
        map.put("planUid", planUid);
        // 这边注意
        map.put("playUrl", url);
        Video record = caseVideoService.getVideoInfoByChn(map);

        // 通道名称
        imageLoad.setChannelsName(record.getChannelsName());
        //Video表uid
        imageLoad.setVideoUid(record.getUid());
        // 类型--1表示图片，2表示视频
        imageLoad.setType("2");

        User user1 = (User) SecurityUtils.getSubject().getSession().getAttribute("user");
        String userUid = user1.getUid();

        // 创建人
        // 用户编号
        imageLoad.setCreatUserUid(userUid);

        Plan planInfo = casePlanService.selectPlanByUid(planUid);
        Case caseInfo = casePlanService.selectCaseByUid(planInfo.getCaseUid());
        //案件类型
        imageLoad.setCaseType(Constants.CASE_TYPE_MAP.get(caseInfo.getCategory()).getName());
        // 视屏开始时间
        imageLoad.setStartTime(start);
        imageLoad.setEndTime(end);
        //caseUid
        imageLoad.setCaseUid(caseInfo.getUid());
        //创建和更新时间
        imageLoad.setDateCreated(new Date());
        imageLoad.setLastUpdated(new Date());
        // 法官信息
        imageLoad.setJudgeUserUid(planInfo.getJudgeUserUid());
        //书记员信息
        imageLoad.setSecretaryUserUid(planInfo.getSecretaryUserUid());

        String message = "";
        Process p = null;
        try {
            // p=Runtime.getRuntime().exec("cmd /c " + strCmd);
            p = Runtime.getRuntime().exec(strCmd);
            // 获取进程的错误流
            final InputStream is2 = p.getErrorStream();
            // 启动一个线程另一个负责读标准错误流
            new Thread() {
                public void run() {
                    BufferedReader br2 = new BufferedReader(new InputStreamReader(is2));
                    try {
                        String line2 = null;
                        while ((line2 = br2.readLine()) != null) {
                            if (line2 != null) {
                            }
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            is2.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }.start();
            // 进行阻塞
            p.waitFor();
            message = "视频截取成功";
            imageLoadService.insert(imageLoad);

        } catch (Exception e) {
            message = "视频截取失败";
            logger.error(e.getMessage());
            return ResultResponse.init(1, message);
        } finally {
            if (null != p) {
                // 释放资源
                p.destroy();
            }
        }
        return ResultResponse.init(0, message);
    }

    @RequestMapping("selectImageByCondition")
    public ResultResponse selectImagePage(String start, String end, String
            type, @RequestParam(value = "userUidList") List<String> userUidList, int page, int pageSize) {
        if (ObjectUtils.isEmpty(page) || page < 1 || ObjectUtils.isEmpty(pageSize) || pageSize < 1) {
            return ResultResponse.failed(ResultCode.PARAMETER_NULL);
        }
        Page<ScreenshotPojo> images = imageLoadService.selectImagePage(start, end, type, userUidList, page, pageSize);
        Map<String, Object> result = new HashMap<>();
        result.put("count", images.getTotal());
//        List<ScreenshotPojo> list = new ArrayList<>();
        for (int i = 0; i < images.getResult().size(); i++) {
            ScreenshotPojo pojo = images.get(i);
            pojo.setEndTimeStr(DateUtils.secToTime(pojo.getEndTime()));
            pojo.setStartTimeStr(DateUtils.secToTime(pojo.getStartTime()));
//            list.add(pojo);
        }
        result.put("data", images.getResult());
        return ResultResponse.success(result);
    }

    @RequestMapping("selectJudgeImageByCondition")
    public ResultResponse selectJudgeImageByCondition(SearchCriteria searchCriteria) {
        if (ObjectUtils.isEmpty(searchCriteria.getPage()) || searchCriteria.getPage() < 1 || ObjectUtils.isEmpty(searchCriteria.getPageSize()) || searchCriteria.getPageSize() < 1) {
            return ResultResponse.failed(ResultCode.PARAMETER_NULL);
        }
        Page<ScreenshotPojo> images = imageLoadService.selectJudgeImageByCondition(searchCriteria);
        Map<String, Object> result = new HashMap<>();
        result.put("count", images.getTotal());
//        List<ScreenshotPojo> list = new ArrayList<>();
        for (int i = 0; i < images.getResult().size(); i++) {
            ScreenshotPojo pojo = images.get(i);
            pojo.setEndTimeStr(DateUtils.secToTime(pojo.getEndTime()));
            pojo.setStartTimeStr(DateUtils.secToTime(pojo.getStartTime()));
//            list.add(pojo);
        }
        result.put("data", images.getResult());
        return ResultResponse.success(result);
    }

    @RequestMapping("del")
    public ResultResponse delete(long id) {
        if (ObjectUtils.isEmpty(id)) {
            return ResultResponse.failed(ResultCode.PARAMETER_NULL);
        }
        return ResultResponse.success(imageLoadService.deleteByPrimaryKey(id));
    }

    public String mkdir(String prefix) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        String path = prefix + calendar.get(Calendar.YEAR) + "/" + (calendar.get(Calendar.MONTH) + 1);
        // 创建多级包
        File file = new File(path);
        if (!file.exists()) {
            file.mkdirs();
            logger.info(path + "多级目录创建成功");
        }
        return path;
    }

    public static String sub(String s) {
        //String a="http://localhost:8080/movies1/82adbfc91b8048b7bbf88913e61cad79/20170125/205.64.2.70_20170125_092009_1.mp4";
        s = s.substring(s.lastIndexOf("_") + 1, s.lastIndexOf("."));
        return s;
    }

    public String getFileName(String url) {
        String temp = url.split(":")[2];
        return temp.substring(temp.indexOf("/") + 1);
    }

    /**
     * 时间轴截图 单命令
     * 性能与当前视频有关导致性能极差，暂时弃用，使用timeline2方法
     *
     * @param uid
     * @return
     */
    @Deprecated
    @RequestMapping("/timeline")
    public ResultResponse timeline(String uid) {
        Video video = videoService.selectByUid(uid);
        if (ObjectUtils.isEmpty(video)) {
            return ResultResponse.init(1, "视频记录未找到");
        }
        Process p = null;
        try {
            String path = Constants.TIMELINE_PATH + "/" + video.getUid() + "/";
            File file = new File(path);
            if (!file.exists()) {
                file.mkdirs();
            }
            logger.info(path);
            String command = Constants.FFMPEG_DIR + "ffmpeg" + " -loglevel quiet -i " + video.getPlayUrl() + " -vf fps=1/20 -s 160*90 " + path + "%5d.png";
            logger.info("命令：" + command);
            p = Runtime.getRuntime().exec(command);
            // 进行阻塞
            p.waitFor();
            p.destroy();
            File f = new File(path);
            File fa[] = f.listFiles();
            List<String> picAddress = new ArrayList<>();
            logger.info(Arrays.toString(file.listFiles()));
            for (File fs : fa) {
                logger.info("fa  fs:--->" + fs.toString());
                if (!fs.isDirectory()) {
                    picAddress.add(path + fs.getName());
                }
            }
            return ResultResponse.success(picAddress);
        } catch (Exception e) {
            logger.error(e.getMessage());
            e.printStackTrace();
        } finally {
            if (null != p) {
                // 释放资源
                try {
                    p.getErrorStream().close();
                    p.getOutputStream().close();
                    p.getInputStream().close();
                    p.destroy();
                } catch (IOException e) {
                    logger.error(e.getMessage());
                }
            }
        }
        return ResultResponse.init(1, "截图失败");
    }

    @Deprecated
    @RequestMapping("/timeline3")
    public ResultResponse timeline3(String uid, long timeSize) {
        Video video = videoService.selectByUid(uid);
        if (ObjectUtils.isEmpty(video)) {
            return ResultResponse.init(1, "视频记录未找到");
        }
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
        simpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT+0"));//**TimeZone时区，加上这句话就解决啦**
        logger.info(String.valueOf(System.currentTimeMillis()));
        Process p = null;
        try {
            String path = Constants.TIMELINE_PATH + "/" + video.getUid() + "/";
            File file = new File(path);
            if (!file.exists()) {
                file.mkdirs();
            }
            logger.info(path);
            p = Runtime.getRuntime().exec("su");
            DataOutputStream outputStream = new DataOutputStream(p.getOutputStream());
            for (int i = 0; i < timeSize; i += 20) {
                outputStream.writeBytes(Constants.FFMPEG_DIR + "ffmpeg" + " -n -ss " + simpleDateFormat.format(i * 1000) + " -i " + video.getPlayUrl() + " -s 240*120 " + path + simpleDateFormat.format(i * 1000) + ".png \n");
            }
            outputStream.flush();
            // 进行阻塞
            p.waitFor();
            p.destroy();
        } catch (Exception e) {
            logger.error(e.getMessage());
            e.printStackTrace();
        } finally {
            if (null != p) {
                // 释放资源
                try {
                    p.getErrorStream().close();
                    p.getOutputStream().close();
                    p.getInputStream().close();
                    p.destroy();
                } catch (IOException e) {
                    logger.error(e.getMessage());
                }
            }
        }
        logger.info(String.valueOf(System.currentTimeMillis()));
        String path = "http://" + Constants.CENTRAL_IP + Constants.CENTRAL_PORT + Constants.TIMELINE_PATH + "/" + video.getUid() + "/";
        File f = new File(path);
        File fa[] = f.listFiles();
        List<String> picAddress = new ArrayList<>();
        logger.info("fa  :--->" + Arrays.toString(fa));
        for (File fs : fa) {
            logger.info("fa  fs:--->" + fs.toString());
            if (!fs.isDirectory()) {
                picAddress.add(path + fs.getName());
            }
        }
        return ResultResponse.success(picAddress);
    }

}
